package blog.gui;

import javax.microedition.lcdui.*;

import blog.SysRuntime;

/**
 * This class displays a list of blog entries in the entry cache.
 * The user can select one or more blog entries to post, edit, or delete.
 *
 */
public abstract class BaseCamDisplay extends Canvas implements CommandListener, CameraViewer
{
	protected int curState;

	int baseWidth;

	int baseHeight;

	Item imgItem;

	int curReqEncoding = ENCODING_IMG_UNKNOWN;//XXX was: jpeg

	String previewMediaType = "image/jpeg";

	String curMediaName;

	byte[] curMediaData;

	byte[] curThumbData;

	protected int encodingWidth = 160; //for capture

	protected int encodingHeight = 120;

	protected int viewWidth; //for display 

	protected int viewHeight;

	Image snapShotImage;

	//commands
	Command cmd_startRec;

	Command cmd_recPhoto;

	Command cmd_recVideo;

	Command cmd_saveData;

	Command cmd_stopRec;

	Command cmd_Reset;

	Command cmd_Back;

	Command[] setSizeCmds;

	int curSizeIdx = 0;

	int cWhiteOutBackground = 0;

	protected static final String IMG_FORMAT_WIDTH = "&width=";

	protected static final String IMG_FORMAT_HEIGHT = "&height=";

	public static final String MI_REC_VIDEO = "Record Video";

	public static final String MI_REC_PHOTO = "Take Photo";

	public static final String MI_SAVE_DATA = "Save";

	public static final String MI_RESET = "Reset";

	public static final String MI_START = "Capture";

	public static final String MI_STOP = "Stop";

	public static final String MI_CANCEL = "Cancel";

	public static final String MI_SIZE_60x80 = "60x80"; //"portrait" on 3650

	public static final String MI_SIZE_90x120 = "90x120";

	public static final String MI_SIZE_80x60 = "80x60";

	public static final String MI_SIZE_120x90 = "120x90";

	public static final String MI_SIZE_160x120 = "160x120";

	public static final String MI_SIZE_320x240 = "320x240";

	public static final String MI_SIZE_400x300 = "400x300";

	public static final String MI_SIZE_640x480 = "640x480";

	public static final int MI_SIZE_DIMS[][] =
	{
	{ 160, 120 },
	{ 80, 60 },
	{ 120, 90 },
	{ 320, 240 } };

	public static final String[] MI_SIZE_OPTIONS =
	{ MI_SIZE_160x120, MI_SIZE_80x60, MI_SIZE_120x90, MI_SIZE_320x240 };

	/** Creates a new instance of CameraDisplay */
	public BaseCamDisplay()
	{
		//super("Camera");
		curState = STATE_IDLE;

		cmd_recPhoto = new Command( MI_REC_PHOTO, Command.SCREEN, 2 );
		cmd_recVideo = new Command( MI_REC_VIDEO, Command.SCREEN, 2 );
		cmd_saveData = new Command( MI_SAVE_DATA, Command.OK, 1 );
		cmd_startRec = new Command( MI_START, Command.OK, 1 );
		cmd_stopRec = new Command( MI_STOP, Command.STOP, 2 );
		cmd_Reset = new Command( MI_RESET, Command.SCREEN, 2 );
		cmd_Back = new Command( MI_CANCEL, Command.SCREEN, 2 );

		setSizeCmds = new Command[MI_SIZE_OPTIONS.length];
		for (int idx = 0; idx < MI_SIZE_OPTIONS.length; idx++)
		{
			setSizeCmds[idx] = new Command( MI_SIZE_OPTIONS[idx], Command.SCREEN, 3 );

		}

		initCamera( 160, 120 );

	}//BaseCamDisplay

	public void initCamera(int width, int height)
	{
		baseWidth = width;
		baseHeight = height;

		encodingWidth = baseWidth;
		encodingHeight = baseHeight;

		doInitCamera( baseWidth, baseHeight ); //Call this immediately

		setCommandListener( this );

		stateBegin_photoViewFinder( );

		/*

		 String prop = System.getProperty("supports.recording");
		 if ((prop == null) || (prop.equals("false")) ) {
		 stateBegin_photoViewFinder();
		 }
		 else {
		 stateBegin_Idle();   
		 }   
		 */
	}

	protected void keyPressed(int keycode)
	{
		int gameAction = this.getGameAction( keycode );

		switch (this.curState)
		{
		case STATE_PHOTO_VIEWFINDER:
			if (gameAction != 0)
			{
				switch (gameAction)
				{
				case Canvas.FIRE:
					stateBegin_photoRecord( );
					break;

				case Canvas.RIGHT:
					this.curSizeIdx++;
					if (this.curSizeIdx == MI_SIZE_DIMS.length)
					{
						this.curSizeIdx = 0;
					}
					this.doSetImageSize( MI_SIZE_DIMS[curSizeIdx][0], MI_SIZE_DIMS[curSizeIdx][1] );
					break;

				case Canvas.LEFT:
					this.curSizeIdx--;
					if (this.curSizeIdx < 0)
					{
						this.curSizeIdx = MI_SIZE_DIMS.length - 1;
					}
					this.doSetImageSize( MI_SIZE_DIMS[curSizeIdx][0], MI_SIZE_DIMS[curSizeIdx][1] );
					break;

				//default:
				//    viewParent.displayDbgMsg("unk game action: " + gameAction, AlertType.ERROR);
				//    break;

				}
			}
			//else {
			//    viewParent.displayDbgMsg("no game action: " + keycode, AlertType.ERROR);
			//}

			break;

		}
	}//keyPressed

	protected void paint(Graphics gw)
	{
		int w = this.getWidth( );
		int h = this.getHeight( );
		gw.setColor( 0xFFFFFF );
		gw.fillRect( 0, 0, w, h );

		int clipX, clipY, clipH, clipW;
		clipX = gw.getClipX( );
		clipY = gw.getClipY( );

		clipH = gw.getClipHeight( );
		clipW = gw.getClipWidth( );

		switch (curState)
		{
		case STATE_IDLE:
			if (this.snapShotImage != null)
			{
				gw.drawImage( this.snapShotImage, (clipW / 2), (clipH / 2), Graphics.HCENTER | Graphics.VCENTER );
			}
			else
			{
				gw.drawString( "Idle...", (clipW / 2), (clipH / 2), Graphics.HCENTER | Graphics.VCENTER );
			}
			break;

		case STATE_PHOTO_VIEWFINDER:
			//Don't need to render here, because the camera blits directly to screen!
			if (this.cWhiteOutBackground > 0)
			{
				gw.setColor( 0x00FFFFFF ); //white?
				gw.fillRect( 0, 0, clipW, clipH );
				this.cWhiteOutBackground--;
			}
			break;

		case STATE_PHOTO_CAPTURED:
			if (this.snapShotImage != null)
			{
				gw.setColor( 0x0005FF05 ); //greenish
				gw.fillRect( clipX, clipY, clipW, clipH );

				gw.drawImage( this.snapShotImage, (clipW / 2), (clipH / 2), Graphics.HCENTER | Graphics.VCENTER );
			}
			break;

		//case STATE_VIDEO_VIEWFINDER:
		//Don't need to render here, because the camera blits directly to screen!
		//break;

		case STATE_VIDEO_CAPTURED:
			break;
		}

	}//paint

	public void commandAction(Command c, Displayable s)
	{
		if (c.equals( this.cmd_recPhoto ))
		{
			this.stateBegin_photoViewFinder( );
		}
		else if (c.equals( this.cmd_recVideo ))
		{
			this.stateBegin_videoViewFinder( );
		}
		else if (c.equals( cmd_startRec ))
		{
			new Thread() {
				public void run() {
					if (BaseCamDisplay.this.curState == CameraViewer.STATE_PHOTO_VIEWFINDER)
						stateBegin_photoRecord( );
					else if (BaseCamDisplay.this.curState == CameraViewer.STATE_VIDEO_VIEWFINDER)
						stateBegin_videoRecord( );
					
					BaseCamDisplay.this.repaint( );
				}
			}.start();
		}
		else if (c.equals( cmd_Back ))
		{
			doCleanup( );
//			viewParent.childFinished( this );
			SysRuntime.guiManager.back();
		}
		else if (c.equals( cmd_saveData ))
		{
			doSaveDataAndExit( );
		}
		else if (c.equals( cmd_stopRec ))
		{
			if (this.curState == CameraViewer.STATE_VIDEO_RECORDING)
			{
				stateBegin_stopRecording( );
			}
		}
		else if (c.equals( cmd_Reset ))
		{
			this.curMediaData = null;
			this.curMediaName = null;

			if (this.curState == CameraViewer.STATE_PHOTO_CAPTURED)
			{
				stateBegin_photoViewFinder( );
			}
			else if (this.curState == CameraViewer.STATE_VIDEO_CAPTURED)
			{
				stateBegin_videoViewFinder( );
			}
		}
		else
		{

			for (int idx = 0; idx < MI_SIZE_OPTIONS.length; idx++)
			{
				if (c.equals( setSizeCmds[idx] ))
				{

					int[] sizeSelection = MI_SIZE_DIMS[idx];
					doSetImageSize( sizeSelection[0], sizeSelection[1] );

					break;
				}
			}

		}
		
		this.repaint( );
	}//commandAction

	protected void removeAllCommands()
	{
		this.removeCommand( cmd_startRec );
		this.removeCommand( cmd_recPhoto );
		this.removeCommand( cmd_recVideo );
		this.removeCommand( cmd_saveData );
		this.removeCommand( cmd_stopRec );
		this.removeCommand( cmd_Reset );
		this.removeCommand( cmd_Back );

		for( int i=0; i<this.setSizeCmds.length; i++ )
		{
			this.removeCommand( setSizeCmds[i] );
		}
	}//removeAllCommands

	/***
	 * All the state transition methods follow.
	 */

	/**
	 *  We're not recording or viewfinding at the moment
	 */
	protected void stateBegin_Idle()
	{
		removeAllCommands( );
		this.addCommand( cmd_recPhoto );
		this.addCommand( cmd_recVideo );
		this.addCommand( cmd_Back );
	}//stateBegin_Idle

	protected void stateBegin_stopRecording()
	{

	}

	protected void stateBegin_photoViewFinder()
	{
		this.snapShotImage = null;
		this.curMediaData = null;
		this.curMediaName = null;

		removeAllCommands( );
		this.addCommand( cmd_startRec );
		this.addCommand( cmd_Back );
		for (int idx = 0; idx < MI_SIZE_OPTIONS.length; idx++)
		{
			this.addCommand( this.setSizeCmds[idx] );
		}

		this.curState = CameraViewer.STATE_PHOTO_VIEWFINDER;
		doDisplayViewFinder( );
		this.doSetImageSize( MI_SIZE_DIMS[curSizeIdx][0], MI_SIZE_DIMS[curSizeIdx][1] );
	}//stateBegin_photoViewFinder

	/**
	 * Capture a photo.
	 */
	protected void stateBegin_photoRecord()
	{
		this.curState = CameraViewer.STATE_PHOTO_RECORDING;
		doRecordPhoto( ); //capture photo data
		stateBegin_photoCaptured( );
	}//stateBegin_photoRecord

	/**
	 * We've captured a photo...now we can display or save it.
	 */
	protected void stateBegin_photoCaptured()
	{
		removeAllCommands( );

		this.addCommand( cmd_saveData );
		this.addCommand( cmd_Reset );
		this.addCommand( cmd_Back );

		this.curState = CameraViewer.STATE_PHOTO_CAPTURED;

	}//stateBegin_photoCaptured

	/***
	 * All the state transition methods follow.
	 */
	protected void stateBegin_videoViewFinder()
	{
		this.curState = CameraViewer.STATE_VIDEO_VIEWFINDER;

		this.snapShotImage = null;
		this.curMediaData = null;
		this.curMediaName = null;

		removeAllCommands( );
		this.addCommand( cmd_startRec );
		this.addCommand( cmd_Back );

		doDisplayViewFinder( );
	}//stateBegin_videoViewFinder

	/**
	 * Capture a photo.
	 */
	protected void stateBegin_videoRecord()
	{
		removeAllCommands( );
		this.addCommand( cmd_stopRec );
		//this.addCommand(cmd_Back);

		this.curState = CameraViewer.STATE_VIDEO_RECORDING;
		doStartVideoRecord( );
	}

	/**
	 * We've captured a photo...now we can display or save it.
	 */
	protected void stateBegin_videoCaptured()
	{
		this.curState = CameraViewer.STATE_VIDEO_CAPTURED;

		removeAllCommands( );
		this.addCommand( cmd_saveData );
		this.addCommand( cmd_Reset );
		this.addCommand( cmd_Back );

	}

	public abstract void doCleanup();

	/** @returns raw byte array of captured image data
	 */
	public byte[] getCaptureData()
	{
		return this.curMediaData;
	}

	/** @return One of the STATE_FOO constants
	 */
	public int getViewState()
	{
		return this.curState;
	}

	/** @param reqEncoding The desired type of encoding data.
	 *
	 * @returns Zero if no problem, something else if there's a problem.
	 */
	public int setEncoding(int reqEncoding)
	{
		curReqEncoding = reqEncoding;
		return 0;
	}

	/** @param viewState One of the STATE_VIDEO, STATE_PHOTO constants
	 */
	public void setViewState(int viewState)
	{
		switch (viewState)
		{
		case CameraViewer.STATE_PHOTO_VIEWFINDER:

			break;

		case CameraViewer.STATE_PHOTO_RECORDING:

			break;

		case CameraViewer.STATE_PHOTO_CAPTURED:

			break;

		}
	}//setViewState

	/**
	 * @returns one of the standard encoding constants
	 */
	public int getEncoding()
	{
		return this.curReqEncoding;
	}

	/** @param The callback client interested in receiving finished status.
	 */

	/*
	 public void setBlogParent(BlogMgr parent) {
	 this.blogParent = parent;
	 this.setViewParent(parent);
	 }
	 **/

	/** @returns String A name for the captured media, if any.
	 */
	public String getMediaName()
	{
		String fullName = this.curMediaName;

		if (ENCODING_IMG_JPEG == this.curReqEncoding)
			fullName += ".jpg";
		else if (ENCODING_IMG_PNG == this.curReqEncoding)
			fullName += ".png";
		else if (ENCODING_IMG_GIF == this.curReqEncoding)
			fullName += ".gif";
		else fullName += ".jpg";

		return fullName;
	}

	public String getMediaType()
	{
		String szMediaType = null;

		switch (this.curReqEncoding)
		{
		case (ENCODING_IMG_JPEG):
			szMediaType = "image/jpeg";
			break;
		case (ENCODING_IMG_PNG):
			szMediaType = "image/png";
			break;
		case (ENCODING_IMG_GIF):
			szMediaType = "image/gif";
			break;
		case (ENCODING_IMG_BMP):
			szMediaType = "image/bmp";
			break;

		}
		//return this.previewMediaType;
		return szMediaType;

	}

//	public void setViewParent(KViewParent parent)
//	{
//		this.viewParent = parent;
//	}

	//=== doFoo methods implemented by subclasses

	protected void doRecordPhoto()
	{
		//empty impl
	}

	protected abstract void doDisplayViewFinder();

	protected void doStartVideoRecord()
	{
		//empty impl
	}

	protected int doInitCamera(int baseWidth, int baseHeight)
	{
		return 0;
	}
	
	public abstract void doSaveDataAndExit();

	/** gets a thumbnail of the captured data, if poossible
	 */
	public Image getThumbnail(int width, int height)
	{
		Image thumbImg = this.snapShotImage;
		if (this.curThumbData != null)
			thumbImg = Image.createImage( curThumbData, 0, curThumbData.length );
		return thumbImg;
	}

	/** Sets an initial image to be displayed before capturing a new image
	 */
	public void setInitialImage(Image startImage)
	{
		this.snapShotImage = startImage;
	}

	protected void doSetImageSize(int w, int h)
	{
		this.encodingWidth = w;
		this.encodingHeight = h;

		cWhiteOutBackground = 10; //clear background before redrawing

	}

}//class BaseCamDisplay
